package com.example.androidcaculator.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class Calculator {

    //将原中缀表达式转换为list结构
    private static List<String> expressionToList(String expression) {
        int index = 0;
        List<String> list = new ArrayList<>();
        do {
            char ch = expression.charAt(index);
            if ((ch < 47 || ch > 58) && ch != '.' && ch != '%') {
                // 是操作符直接添加到list中
                index++;
                list.add(ch + "");
            } else if (ch >= 47 && ch <= 58) {
                // 是数字，判断多位数情况
                String str = "";
                while (index < expression.length() && expression.charAt(index) >= 47 && expression.charAt(index) <= 58
                        || index < expression.length() && expression.charAt(index) == '.') {
                    str += expression.charAt(index);
                    index++;

                    if (index < expression.length() && expression.charAt(index) == '%') {
                        //如股票数字遍历完后下一位是百分号，则除以100后再入队
                        str = String.valueOf(Double.parseDouble(str) / 100);
                        index++;
                    }

                }
                list.add(str);

            }

        } while (index < expression.length());
        return list;
    }

    //判断是否为操作符
    public static boolean isOperator(String op) {
        return op.equals("+") || op.equals("-") || op.equals("×") || op.equals("÷");
    }

    //判断是否为数
    public boolean isNum(String num) {
        if (num.matches("\\d+")) // 判断整数
            return true;
        else {
            boolean tag = false;
            for (int i = 0; i < num.length(); i++) {
                if (num.charAt(i) == '.') // 判断小数
                    tag = true;
                else if (num.charAt(i) < 47 || num.charAt(i) > 58)
                    return false;
            }
            return tag;
        }

    }

    //判断操作数的优先级
    public static int priority(String op) {
        if (op.equals("×") || op.equals("÷"))
            return 1;
        else if (op.equals("+") || op.equals("-"))
            return 0;
        return -1;
    }


    //将中缀表达式转换为后缀表达式
    private List<String> parseToSuffixExpression(List<String> expressionList) {

        Stack<String> opStack = new Stack<>(); //保存操作符的栈
        List<String> suffixList = new ArrayList<>(); //保存后缀表达式的list

        for (String item : expressionList) {
            //得到数或操作符
            if (isOperator(item)) {
                //是操作符，判断操作符栈是否为空
                if (opStack.isEmpty() || "(".equals(opStack.peek()) || priority(item) > priority(opStack.peek())) {
                    //如果栈为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符时直接压栈
                    opStack.push(item);
                } else {
                    //否则将栈中元素出栈，直到遇到优先级大于当前操作符或者左括号为止
                    while (!opStack.isEmpty() && !"(".equals(opStack.peek())) {
                        if (priority(item) <= priority(opStack.peek()))
                            suffixList.add(opStack.pop());
                    }
                    //接着将当前操作符压栈
                    opStack.push(item);

                }

            } else if (isNum(item)) {
                //是数字则直接入列
                suffixList.add(item);
            } else if ("(".equals(item)) {
                //是左括号则压栈
                opStack.push(item);
            } else if (")".equals(item)) {
                //是右括号，则将栈中元素弹出入队，直到遇到左括号，左括号出栈，但不入队
                while (!opStack.isEmpty()) {
                    if ("(".equals(opStack.peek())) {
                        opStack.pop();
                        break;
                    } else
                        suffixList.add(opStack.pop());

                }

            } else {
                throw new RuntimeException("有非法字符！");
            }


        }

        //遍历表达式完毕后，如果操作符栈中元素不为空，将栈中元素出栈入队
        while (!opStack.isEmpty()) {
            suffixList.add(opStack.pop());
        }

        return suffixList;


    }

    //计算表达式结果
    public Double calculate(String expression) {
        List<String> list = parseToSuffixExpression(expressionToList(expression));
        Stack<Double> stack = new Stack<>();
        for (int i = 0; i < list.size(); i++) {
            String item = list.get(i);
            if (isNum(item)) {
                //是数字直接压栈
                stack.push(Double.parseDouble(item));
            } else {
                //是操作数取出栈顶两个元素运算
                double num2 = stack.pop();
                double num1 = stack.pop();
                double result = 0;
                if (item.equals("+"))
                    result = num1 + num2;
                else if (item.equals("-"))
                    result = num1 - num2;
                else if (item.equals("×"))
                    result = num1 * num2;
                else if (item.equals("÷"))
                    result = num1 / num2;
                else {
                    throw new RuntimeException("运算符错误！");
                }

                stack.push(result);
            }


        }
        return stack.pop();
    }

    //计算阶乘
    public long factorial(int number){
        if (number <=1)
            return 1;
        else return number*factorial(number-1);

    }


}
